Resizegrad

计算 Resize 操作的梯度。该算子包含两种实现:最近邻插值梯度(ResizeNearestNeighborGrad)和双线性插值梯度(ResizeBiLinearGrad)。用于将上游梯度从输出尺寸反向传播到输入尺寸。

最近邻插值梯度(ResizeNearestNeighborGrad)

对于最近邻插值,输入梯度通过最近邻映射反向传播到输出梯度。

\[\begin{split}out_y = \begin{cases} \mathrm{round}(in_y \cdot height\_scale), & \text{if } align\_corners \\ \lfloor in_y \cdot height\_scale \rfloor, & \text{otherwise} \end{cases}\end{split}\]
\[\begin{split}out_x = \begin{cases} \mathrm{round}(in_x \cdot width\_scale), & \text{if } align\_corners \\ \lfloor in_x \cdot width\_scale \rfloor, & \text{otherwise} \end{cases}\end{split}\]
\[out\_addr[out\_offset] \mathrel{+}= in\_addr[in\_offset]\]

其中 in_addr 是上游梯度(输出尺寸),out_addr 是输入梯度(输入尺寸)。注意使用累加操作(+=),因为多个输入位置可能映射到同一个输出位置。

双线性插值梯度(ResizeBiLinearGrad)

对于双线性插值,输入梯度通过双线性插值的反向传播分配到4个相邻的输出位置。

\[in_y = h \cdot height\_scale\]
\[top_y = \max(\lfloor in_y \rfloor, 0)\]
\[bottom_y = \min(\lceil in_y \rceil, out\_height - 1)\]
\[y_{\mathrm{lerp}} = in_y - \lfloor in_y \rfloor\]
\[inverse\_y\_lerp = 1.0 - y_{\mathrm{lerp}}\]

对于 x 维度有类似的公式:

\[in_x = w \cdot width\_scale\]
\[left_x = \max(\lfloor in_x \rfloor, 0)\]
\[right_x = \min(\lceil in_x \rceil, out\_width - 1)\]
\[x_{\mathrm{lerp}} = in_x - \lfloor in_x \rfloor\]
\[inverse\_x\_lerp = 1.0 - x_{\mathrm{lerp}}\]

输入梯度按权重分配到4个相邻位置:

\[out\_addr[top_y, left_x] \mathrel{+}= in\_addr[h, w] \cdot (inverse\_y\_lerp \cdot inverse\_x\_lerp)\]
\[out\_addr[top_y, right_x] \mathrel{+}= in\_addr[h, w] \cdot (inverse\_y\_lerp \cdot x_{\mathrm{lerp}})\]
\[out\_addr[bottom_y, left_x] \mathrel{+}= in\_addr[h, w] \cdot (y_{\mathrm{lerp}} \cdot inverse\_x\_lerp)\]
\[out\_addr[bottom_y, right_x] \mathrel{+}= in\_addr[h, w] \cdot (y_{\mathrm{lerp}} \cdot x_{\mathrm{lerp}})\]
输入:
  • in_addr - 指向上游梯度数据的指针(输出尺寸的梯度)。

  • out_addr - 指向输出梯度数据的指针(输入尺寸的梯度),需要初始化为0。

  • batch_size - 批次大小。

  • channel - 通道数。

  • format - 数据格式,0 表示 NHWC,1 表示 NCHW。

  • align_corners - 是否对齐角点标志,0 表示不对齐,1 表示对齐。

  • in_height - 输入高度。

  • in_width - 输入宽度。

  • out_height - 输出高度。

  • out_width - 输出宽度。

  • height_scale - 高度缩放因子,通常为 (out_height - 1) / (in_height - 1) 或 out_height / in_height。

  • width_scale - 宽度缩放因子,通常为 (out_width - 1) / (in_width - 1) 或 out_width / in_width。

输出:
  • out_addr - 计算后的输入梯度(输入尺寸的梯度)。

支持平台:

FT78NE MT7004

备注

  • FT78NE 支持 fp32

  • MT7004 支持 fp16, fp32

共享存储版本:

void fp_resizenearestneighborgrad_s(float *in_addr, float *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask)
void hp_resizenearestneighborgrad_s(half *in_addr, half *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask)
void fp_resizebilineargrad_s(float *in_addr, float *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask)
void hp_resizebilineargrad_s(half *in_addr, half *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale, int core_mask)

C调用示例(最近邻插值梯度):

 1#include <stdio.h>
 2#include <resizegrad.h>
 3
 4int main(int argc, char* argv[]) {
 5    float *in_addr = (float *)0x10010000;
 6    float *out_addr = (float *)0x10020000;
 7
 8    int batch_size = 4;
 9    int channel = 3;
10    int format = 1;
11    int align_corners = 1;
12    int in_height = 4, in_width = 4;
13    int out_height = 6, out_width = 6;
14    int core_mask = 0xff;
15
16    float height_scale = (float)(out_height - 1) / (in_height - 1);
17    float width_scale = (float)(out_width - 1) / (in_width - 1);
18
19    int output_size = in_height * in_width * channel * batch_size;
20    memset(out_addr, 0, output_size * sizeof(float));
21
22    fp_resizenearestneighborgrad_s(in_addr, out_addr, batch_size, channel,
23                                    format, align_corners, in_height, in_width,
24                                    out_height, out_width, height_scale, width_scale, core_mask);
25    return 0;
26}

私有存储版本:

void fp_resizenearestneighborgrad_p(float *in_addr, float *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale)
void hp_resizenearestneighborgrad_p(half *in_addr, half *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale)
void fp_resizebilineargrad_p(float *in_addr, float *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale)
void hp_resizebilineargrad_p(half *in_addr, half *out_addr, int batch_size, int channel, int format, int align_corners, int in_height, int in_width, int out_height, int out_width, float height_scale, float width_scale)

C调用示例(双线性插值梯度):

 1#include <stdio.h>
 2#include <resizegrad.h>
 3
 4int main(int argc, char* argv[]) {
 5    float *in_addr = (float *)0x10010000;
 6    float *out_addr = (float *)0x10020000;
 7
 8    int batch_size = 4;
 9    int channel = 3;
10    int format = 0;
11    int align_corners = 0;
12    int in_height = 4, in_width = 4;
13    int out_height = 6, out_width = 6;
14
15    float height_scale = (float)out_height / in_height;
16    float width_scale = (float)out_width / in_width;
17
18    int output_size = in_height * in_width * channel * batch_size;
19    memset(out_addr, 0, output_size * sizeof(float));
20
21    fp_resizebilineargrad_p(in_addr, out_addr, batch_size, channel,
22                             format, align_corners, in_height, in_width,
23                             out_height, out_width, height_scale, width_scale);
24    return 0;
25}